package com.hyl.config;

import com.hyl.types.annotations.DCCValue;
import com.hyl.types.common.Constants;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RBucket;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet.CloudFoundryHealthEndpointWebExtension;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;



/**
 * @author hyl
 * @description
 * @create 2025-06-19 15:57
 */
@Slf4j
@Configuration
public class DCCValueBeanFactory implements BeanPostProcessor {

    private static final String BASE_CONFIG_PATH = "group_buy_market_dcc_";

    private final RedissonClient redissonClient;

    private final Map<String,Object> docObjGroup = new HashMap<>();



    public DCCValueBeanFactory(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }
    @Bean("docTopic")
    public RTopic dccRedisTopicLostener(RedissonClient redissonClient){
        RTopic topic = redissonClient.getTopic("group_buy_market_dcc");
        topic.addListener(String.class, (charSequence, s) -> {
            String[] split = s.split(Constants.SPLIT);
            //获取值
            String attribute = split[0];
            String key = BASE_CONFIG_PATH+attribute;
            String Value = split[1];

            //设置值
            RBucket<String> bucket = redissonClient.getBucket(key);
            boolean exists = bucket.isExists();
            if (!exists) return;
            bucket.set(Value);

            Object objBean = docObjGroup.get(key);
            if (objBean == null)return;
            Class<?> objeBeanClass = objBean.getClass();
            //检查objBean是否是代理对象
            if (AopUtils.isAopProxy(objBean)){
                objeBeanClass = AopUtils.getTargetClass(objBean);
            }
            try {
                // 1. getDeclaredField 方法用于获取指定类中声明的所有字段，包括私有字段、受保护字段和公共字段。
                // 2. getField 方法用于获取指定类中的公共字段，即只能获取到公共访问修饰符（public）的字段。
                Field field = objeBeanClass.getDeclaredField(attribute);
                field.setAccessible(true);
                field.set(objBean, Value);
                field.setAccessible(false);

                log.info("DCC 节点监听，动态设置值 {} {}", key, Value);
            }catch (Exception e){
                throw new RuntimeException(e);
            }
        });
        return topic;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

        Class<?> targetBeanClass = bean.getClass();
        Object targetBeanObject = bean;
        if (AopUtils.isAopProxy(bean)){
            targetBeanClass = AopUtils.getTargetClass(bean);
            targetBeanObject = AopProxyUtils.getSingletonTarget(bean);

        }
        Field[] fields = targetBeanClass.getDeclaredFields();
        for (Field field : fields){
            if (!field.isAnnotationPresent(DCCValue.class)){
                continue;
            }

            DCCValue dccValue = field.getAnnotation(DCCValue.class);
            String value = dccValue.value();
            if (StringUtils.isBlank(value)){
                throw new RuntimeException(field.getName()+" @DCCValue is not config value config case 「isSwitch/isSwitch:1」");

            }
            String[] splits = value.split(":");
            String key = BASE_CONFIG_PATH.concat(splits[0]);
            String defaultValue = splits.length == 2 ? splits[1] : null;

            //设置值
            String setValue = defaultValue;
            try {
                if (StringUtils.isBlank(defaultValue)){
                    throw new RuntimeException("dcc config error " + key + " is not null - 请配置默认值！");
                }
                RBucket<String> bucket = redissonClient.getBucket(key);
                boolean exists = bucket.isExists();
                if (!exists){
                    bucket.set(defaultValue);
                }else {
                    setValue = bucket.get();
                }
                field.setAccessible(true);
                field.set(targetBeanObject,setValue);
                field.setAccessible(false);

            }catch (Exception e){
                throw new RuntimeException(e);
            }

            docObjGroup.put(key, targetBeanObject);
        }
        return bean;


    }



}




